﻿

IncludePath "Source/"
IncludeFile "threeD.pb"
IncludePath "/"

;EnableExplicit

#Program_WindowNum = 0

;{ Structures
Structure vertex
	pos.vec3
EndStructure
;}
;{ Globals
Global ModelShaderID.l
Global PosteffectShaderID.l
Global TextureID.l
Global hDC.l
Global fboID.l


Global MatProj.mat4
Global MatModelView.mat4

Global *quad.VAO
Global *mesh.AnimatedMesh
Global *lightMesh.Mesh
Global frameNumber.f = 0
;}
	
Procedure.l CreateFullscreenQuad()
	Protected Dim vertices.vec3(4)
	Protected Dim texcoords.vec2(4)
	Protected Dim indices.l(6)
	Protected Dim normals.vec3(0), Dim tangents.vec3(0) ;no normals
	
	vertices(0)\x = -1.0 : vertices(0)\y = -1.0 : texcoords(0)\x = 0.0 : texcoords(0)\y = 0.0
	vertices(1)\x =  1.0 : vertices(1)\y = -1.0 : texcoords(1)\x = 1.0 : texcoords(1)\y = 0.0
	vertices(2)\x =  1.0 : vertices(2)\y =  1.0 : texcoords(2)\x = 1.0 : texcoords(2)\y = 1.0
	vertices(3)\x = -1.0 : vertices(3)\y =  1.0 : texcoords(3)\x = 0.0 : texcoords(3)\y = 1.0
	
	indices(0) = 0
	indices(1) = 2;1
	indices(2) = 1;2
	indices(3) = 0
	indices(4) = 3;2
	indices(5) = 2;3

	ProcedureReturn CreateVAO2(vertices(), normals(), tangents(), texcoords(), indices(), #GL_STATIC_DRAW)
EndProcedure

Structure FrameBufferAttachement
	ID.l
	
EndStructure

Structure FrameBufferObject
	ID.l
	StencilRenderbufferID.l
	DepthAttachementID.l
	ColorAttachementID.l[16]
EndStructure

Global Dim fboTextures(2)
Procedure CreateOrUpdateFBO(width.l, height.l)
	Static.l fboID = 0, depthbufferID = 0
	
	;Clean up old FBO and all attachements
	If fboID <> 0
		If depthbufferID <> 0
			glDeleteRenderbuffers(1, @depthbufferID)
		EndIf
		
		glDeleteTextures(3, @fboTextures())
		
		glDeleteFramebuffers(1, @fboID)
	EndIf
	
	;Create new FBO
	glGenFramebuffers(1, @fboID)
	glBindFramebuffer (#GL_FRAMEBUFFER, fboID)
	
	;depth buffer
  glGenRenderbuffers(1, @depthbufferID)
  glBindRenderbuffer(#GL_RENDERBUFFER, depthbufferID )
  glRenderbufferStorage(#GL_RENDERBUFFER, #GL_DEPTH_COMPONENT, width, height)
  glFramebufferRenderbuffer(#GL_FRAMEBUFFER,  #GL_DEPTH_ATTACHMENT, #GL_RENDERBUFFER, depthbufferID)
  
  ;three color buffers
  fboTextures(0) = OpenGL_CreateColorRectTexture(#GL_RGBA, #GL_RGBA32F, width, height)
  fboTextures(1) = OpenGL_CreateColorRectTexture(#GL_RGBA, #GL_RGBA32F, width, height)
  fboTextures(2) = OpenGL_CreateColorRectTexture(#GL_RGBA, #GL_RGBA32F, width, height)
  
  glBindTexture_(#GL_TEXTURE_RECTANGLE, fboTextures(0))
  glFramebufferTexture(#GL_FRAMEBUFFER, #GL_COLOR_ATTACHMENT0, fboTextures(0), 0)
  glBindTexture_(#GL_TEXTURE_RECTANGLE, fboTextures(1))
  glFramebufferTexture(#GL_FRAMEBUFFER, #GL_COLOR_ATTACHMENT1, fboTextures(1), 0)
  glBindTexture_(#GL_TEXTURE_RECTANGLE, fboTextures(2))
  glFramebufferTexture(#GL_FRAMEBUFFER, #GL_COLOR_ATTACHMENT2, fboTextures(2), 0)
  
  If glCheckFramebufferStatus(#GL_FRAMEBUFFER) = #GL_FRAMEBUFFER_COMPLETE
		Protected Dim buffers(2) : buffers(0) = #GL_COLOR_ATTACHMENT0 : buffers(1) = #GL_COLOR_ATTACHMENT1 : buffers(2) = #GL_COLOR_ATTACHMENT2
		glDrawBuffers (3, @buffers())
		
  	ProcedureReturn fboID
  EndIf
  Debug "fail"	
  
EndProcedure


Procedure UpdateModelMat()
	Protected.vec4 pos, Q, Q1, Q2
	Protected.mat3 MatRot3
	Protected.mat4 MatTrans, MatRot4
	Protected.f angleV, angleH
	
	angleV = WindowMouseY(#Program_WindowNum)/20.0
	angleH = WindowMouseX(#Program_WindowNum)/20.0
	
	;Set model center
	Mat4_CreateTranslationComp(MatTrans, -(*mesh\BBoxMax\x + *mesh\BBoxMin\x)/2.0, -(*mesh\BBoxMax\y + *mesh\BBoxMin\y)/2.0, -(*mesh\BBoxMax\z + *mesh\BBoxMin\z)/2.0)
	
	Quat_FromAxisComp(Q1, 1,0,0, angleV)
	Quat_FromAxisComp(Q2, 0,0,1, angleH)
	Quat_MulQ(Q, Q1, Q2)
	Mat3_FromQuat(MatRot3, Q)
	
	Vec4_Set(pos, 0, 0, -200, 1)
	Mat4_SetM(MatRot4, MatRot3, pos)
	
	Mat4_MulM(MatModelView, MatRot4, MatTrans)
EndProcedure

Procedure Init()
	UsePNGImageDecoder()
	OpenWindow(#Program_WindowNum, 100, 200, 512, 512, "PureBasic Window", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget | #PB_Window_ScreenCentered | #PB_Window_SizeGadget)
	hDC = CreateOpenGLContext(WindowID(0))		
	
	
	
	ModelShaderID = LoadShadersFromFiles("Data/md3shader.vs", "Data/ex06_ds_md3shader.fs", "Data/md3shader.gs")
	PosteffectShaderID = LoadShadersFromFiles("Data/ex06_ds_light_shader.vs", "Data/ex06_ds_light_shader.fs")
	
	TextureID = OpenGL_ImageToTexture(LoadImage(#PB_Any, "Data/skin.png"), -1, #GL_LINEAR)
	
	
	
	Protected mdl.md3entity
	LoadMD3(@mdl, "Data/gman.md3")
	*mesh = CreateAnimatedMeshFromMD3(@mdl)
	
	*lightMesh = CreateSphereMesh(8, 8, 1.0)
	
	*quad = CreateFullscreenQuad()
	
	glClearColor_(0.0,0.0,0.3,1)
	glEnable_(#GL_CULL_FACE)
	glCullFace_(#GL_FRONT)
EndProcedure

Procedure RenderScene()
  Protected.l uniformLocation
  
  glBindFramebuffer(#GL_FRAMEBUFFER, fboID)
  
	glEnable_(#GL_DEPTH_TEST)
	glDepthMask_(#GL_TRUE)
	
	glClear_(#GL_COLOR_BUFFER_BIT | #GL_DEPTH_BUFFER_BIT)
  
	glUseProgram(ModelShaderID)
	
	;Юниформы
	uniformLocation = glGetUniformLocation(ModelShaderID, @"u_ProjectionMat")
	If uniformLocation <> -1
		glUniformMatrix4fv(uniformLocation, 1, #True, @MatProj)
	EndIf
	uniformLocation = glGetUniformLocation(ModelShaderID, @"u_BaseTexture")
	If uniformLocation <> -1
		glUniform1i(uniformLocation, 0)
	EndIf

	glActiveTexture(#GL_TEXTURE0);делаем активным текстурный юнит 0
	glBindTexture(#GL_TEXTURE_2D, TextureID);назначаем текстуру на активный текстурный юнит

	
	;Animation
	frameNumber = frameNumber + 0.01
	If (frameNumber >= *mesh\NumOfFrames)
		frameNumber = 0
	EndIf	
	
	Protected blend.f = frameNumber-Int(frameNumber)
	uniformLocation = glGetUniformLocation(ModelShaderID, @"u_Blend")
	If uniformLocation <> -1
		glUniform1f(uniformLocation, blend)
	EndIf
	
	
	
	Protected.mat4 translation, mw
	For i = -5 To 5
		For j = -5 To 5
			Mat4_CreateTranslationComp(translation, i*40.0, j*40.0, 0.0)
			Mat4_MulM(mw, MatModelView, translation)
			
			uniformLocation = glGetUniformLocation(ModelShaderID, @"u_ModelViewMat")
			If uniformLocation <> -1
				glUniformMatrix4fv(uniformLocation, 1, #True, @mw)
			EndIf	
			
			DrawAnimatedMesh(*mesh, Int(frameNumber), Int(frameNumber)+1, blend)
		Next
	Next
EndProcedure

Procedure RenderPosteffect()
	Protected.l uniformLocation
	
	glBindFramebuffer(#GL_FRAMEBUFFER, 0)
	
	glClear_(#GL_COLOR_BUFFER_BIT )
	
	glDisable_(#GL_DEPTH_TEST)
	glDepthMask_(#GL_FALSE)
	
	;glDrawBuffer_(#GL_BACK)
	
	glUseProgram(PosteffectShaderID)
	
	;Textures
	uniformLocation = glGetUniformLocation(PosteffectShaderID, @"u_texPosition")
	If uniformLocation <> -1
		glUniform1i(uniformLocation, 0)
	EndIf
	uniformLocation = glGetUniformLocation(PosteffectShaderID, @"u_texNormal")
	If uniformLocation <> -1
		glUniform1i(uniformLocation, 1)
	EndIf
	uniformLocation = glGetUniformLocation(PosteffectShaderID, @"u_texColor")
	If uniformLocation <> -1
		glUniform1i(uniformLocation, 2)
	EndIf
	;Lighting
	uniformLocation = glGetUniformLocation(PosteffectShaderID, @"light.position")
	If uniformLocation <> -1
		Protected.vec4 lightPos, lightInitialPos
		Protected.mat4 MWP
		Vec4_Set(lightInitialPos, 10.0, -8.0, 100.0, 1.0)
		Mat4_MulM(MWP, MatProj, MatModelView)
		Mat4_MulV(lightPos, MWP, lightInitialPos)
		glUniform4fv(uniformLocation, 1, @lightPos)
	EndIf
	uniformLocation = glGetUniformLocation(PosteffectShaderID, @"light.diffuseColor")
	If uniformLocation <> -1
		glUniform3f(uniformLocation, 1.0, 1.0, 1.0)
	EndIf
	uniformLocation = glGetUniformLocation(PosteffectShaderID, @"light.specularColor")
	If uniformLocation <> -1
		glUniform3f(uniformLocation, 1.0, 1.0, 0.0)
	EndIf
	uniformLocation = glGetUniformLocation(PosteffectShaderID, @"light.radius")
	If uniformLocation <> -1
		glUniform1f(uniformLocation, 150.0)
	EndIf
	
	uniformLocation = glGetUniformLocation(PosteffectShaderID, @"u_ProjectionMat")
	If uniformLocation <> -1
		glUniformMatrix4fv(uniformLocation, 1, #True, @MatProj)
	EndIf
	uniformLocation = glGetUniformLocation(PosteffectShaderID, @"u_ModelViewMat")
	If uniformLocation <> -1
		glUniformMatrix4fv(uniformLocation, 1, #True, @MatModelView)
	EndIf	
	
	glActiveTexture(#GL_TEXTURE2)
	glBindTexture(#GL_TEXTURE_RECTANGLE, fboTextures(2))
	glActiveTexture(#GL_TEXTURE1)
	glBindTexture(#GL_TEXTURE_RECTANGLE, fboTextures(1))
	glActiveTexture(#GL_TEXTURE0)
	glBindTexture(#GL_TEXTURE_RECTANGLE, fboTextures(0))

	DrawMesh(*lightMesh)
	;glBindVertexArray(*quad\ID)
	;glDrawElements(#GL_TRIANGLES, 6, #GL_UNSIGNED_INT, 0)
EndProcedure


Init()

Repeat
	Event.l = WaitWindowEvent(1)
	Select Event
		Case #PB_Event_CloseWindow	
			Quit = 1
		Case #PB_Event_SizeWindow
			glViewport_(0, 0, WindowWidth(0), WindowHeight(0))
			Mat4_CreatePerspective(MatProj, #PI/2, WindowWidth(0)/WindowHeight(0), 0.1, 1000.0)
			fboID = CreateOrUpdateFBO(WindowWidth(#Program_WindowNum), WindowHeight(#Program_WindowNum))
	EndSelect
	
	UpdateModelMat()

	
	RenderScene();PASS 1
	RenderPosteffect();PASS 2
	
	
	SwapBuffers_(hDC)
Until Quit = 1
; IDE Options = PureBasic 5.11 (Windows - x86)
; CursorPosition = 154
; FirstLine = 132
; Folding = --
; EnableXP